# -*- coding: utf-8 -*-
import logging
import uuid

from flask import request, abort, render_template, current_app
from flask_sqlalchemy import get_debug_queries

from . import api
from . import send_async_email
from .ext import orm
from .models import Domain, DomainCache, ActionLog

LOGGER = logging.getLogger(__name__)


@api.after_request
def after_request(response):
    for query in get_debug_queries():
        if query.duration >= current_app.config['DATABASE_QUERY_TIMEOUT']:
            LOGGER.warn(
                ('\nContext:{}\nSLOW QUERY: {}\nParameters: {}\n'
                 'Duration: {}\n').format(query.context, query.statement,
                                          query.parameters, query.duration))
    return response


@api.route('/domains')
def list_domains():
    """ List domain.

        GET /domains?project_id=pro-abc&name=foo
    =>
        Domain.query.filter_by(project_id=project_id).filter(
            Domain.name.like('%foo%'))

    :return:
    """
    # username = request.headers['user_name']
    args = request.args

    project_id = args['project_id']

    filters = []
    for field, value in args.items():
        if field != 'project_id':
            _filter_by = getattr(Domain, field.lower(), None)
            if _filter_by is None:
                abort(400)
            else:
                filters.append(_filter_by.like('%%%s%%' % value))

    domains = Domain.query.filter_by(project_id=project_id).filter(*filters)
    orm.session.commit()

    resp = {
        'status': 0,
        'msg': 'success',
        'data': [d.to_json() for d in domains],
    }
    return resp


@api.route('/domains', methods=['POST'])
def add_domain():
    """ Append a `domain` record and send a mail.


    JSON request sample:
        {
            "project_id": "proj_xxx",
            "domain_name": "foo",
            "cname": "foo",
            "connect_in": "HTTP",
            "test_url": "http://example.org/test.png",
            "region": "shanghai",
            "protocol": "HTTP",

            "bandwidth_peak": 100,
            "cache_size": 100,
            "set_filter": false,
            "expire_rules": [
                {"type": "file_type", "content": "all|.jpg", "ttl": "30", "unit": "day"},
                {"type": "directory", "content": "/data/repo/foo_d", "ttl": "30", "unit": "day"},
                {"type": "path", "content": "/data/repo/a.png", "ttl": "30", "unit": "day"},
                {"type": "all", "content": "all", "ttl": "30", "unit": "day"},
            ]

        }

    :return:
    """
    username = request.headers['user_name']

    req_data = request.get_json(force=True)

    project_id = req_data['project_id']

    # resource_id = request.form['resource_id']
    resource_id = 'dm-' + uuid.uuid4().hex[:7]
    domain_name = req_data['domain_name']

    cname = req_data.get('cname')
    connect_in = req_data['connect_in']

    test_url = req_data['test_url']

    region = req_data['region']
    protocol = req_data['protocol']

    bandwidth_peak = req_data['bandwidth_peak']
    cache_size = req_data['cache_size']
    set_filter = req_data['set_filter']

    status = req_data.get('status', u'处理中')

    domain = Domain(resource_id, domain_name,
                    cname, connect_in,
                    region, protocol, project_id,
                    bandwidth_peak, cache_size,
                    username, test_url, set_filter, status)

    try:
        orm.session.add(domain)

        for rule in req_data['expire_rules']:
            dc = DomainCache()
            dc.domain_id = resource_id
            dc.domain_cache_id = 'dc-' + uuid.uuid4().hex[:7]
            dc.media_type = rule['type']
            dc.url_template = rule['content']
            dc.ttl = rule['ttl']
            dc.unit = rule['unit']
            orm.session.add(dc)

        # Add action log
        a_log = ActionLog()
        a_log.username = username
        a_log.action_name = u'创建域名'
        a_log.resource_type = 'domain'
        a_log.resource_id = domain.domain_id
        orm.session.add(a_log)

        orm.session.commit()

        resp = {
            'status': 0,
            'msg': 'success',
            'data': 'ok',
        }, 201

        mail_data = {
            'basic': [
                (u'加速域名', domain_name),
                (u'加速区域', region),
                (u'测试URL', test_url),
                (u'加速协议', protocol),
                (u'接入方式', connect_in),
                (u'峰值带宽预估(Mb)', req_data['bandwidth_peak']),
                (u'开启过滤', u'是' if req_data['set_filter'] else u'否'),
                (u'缓存空间预估(Gb)', req_data['cache_size']),
            ],

            'rule_columns': [
                ('type', u'类型'),
                ('content', u'内容'),
                ('ttl', u'缓存时间'),
                ('unit', u'时间单位'),
            ],
            'rules': req_data['expire_rules'],
        }

        subject = u'SCDN域名申请[%s]' % domain_name
        mail_html = render_template('mail.html', user=username, **mail_data)
        send_async_email.delay(subject, username,
                               current_app.config['MAIL_TO'],
                               current_app.config['MAIL_CC'],
                               mail_html)
    except Exception, e:
        LOGGER.exception(e.message)
        orm.session.rollback()

        resp = {
            'status': 1,
            'msg': 'fail',
            'data': str(e.args[0]),
        }

    return resp


@api.route('/domains/<dm_id>', methods=['DELETE'])
def remove_domain(dm_id):
    username = request.headers['user_name']

    dm = Domain.query.filter_by(domain_id=dm_id).first_or_404()

    try:
        orm.session.delete(dm)
        DomainCache.query.filter_by(domain_id=dm_id).delete()
        orm.session.commit()

        resp = {
            'status': 0,
            'data': 'success',
            'msg': u'删除成功'
        }
    except Exception, e:
        orm.session.rollback()
        LOGGER.exception(e.message)
        resp = {
            'status': 1,
            'data': 'fail',
            'msg': u'删除失败'
        }

    # Add action log
    a_log = ActionLog()
    a_log.username = username
    a_log.action_name = u'删除域名'
    a_log.resource_type = 'domain'
    a_log.resource_id = dm.domain_id
    a_log.result = resp['msg']
    orm.session.add(a_log)
    orm.session.commit()

    return resp


@api.route('/domains/<dm_id>/cache_settings', methods=['PUT'])
def replace_domain_cache_setting(dm_id):
    """ Replace the `cache_settings` of domain. """
    username = request.headers['user_name']

    dm = Domain.query.filter_by(domain_id=dm_id).first_or_404()

    dc_settings = request.get_json(force=True)

    try:
        # Delete old rules
        DomainCache.query.filter_by(domain_id=dm_id).delete()

        caches = []
        for dc_setting in dc_settings:
            cache = DomainCache()
            cache.domain_id = dm_id
            cache.domain_cache_id = 'dc-%s' % (uuid.uuid4().hex[:7])

            for attr, val in dc_setting.items():
                setattr(cache, attr, val)

            orm.session.add(cache)
            caches.append(cache)

        orm.session.commit()

        resp = {
            'status': 0,
            'msg': 'success',
            'data': [c.to_json() for c in caches],
        }

        # Send email
        mail_data = {
            'rule_columns': [
                ('priority', u'优先级'),
                ('media_type', u'类型'),
                ('url_template', u'路径模板'),
                ('ttl', u'有效时间'),
                ('unit', u'时间单位'),
                ('enabled', u'是否启用'),
            ],
            'rules': [
                {
                    'priority': dc.priority,
                    'media_type': dc.media_type,
                    'url_template': dc.url_template,
                    'ttl': dc.ttl,
                    'unit': dc.unit,
                    'enabled': dc.enabled,
                }
                for dc in caches
            ]
        }
        subject = u'SCDN缓存规则修改[%s]' % dm.domain_name
        mail_html = render_template('mail_cache.html',
                                    user=username,
                                    **mail_data)
        send_async_email.delay(subject, username,
                               current_app.config['MAIL_TO'],
                               current_app.config['MAIL_CC'],
                               mail_html)
    except:
        orm.session.rollback()
        resp = {
            'status': 1,
            'msg': 'fail',
            'data': u'更新失败'
        }

    # Add action log
    a_log = ActionLog()
    a_log.username = username
    a_log.action_name = u'替换所有缓存规则'
    a_log.resource_type = 'domain'
    a_log.resource_id = dm.domain_id
    a_log.result = resp['msg']
    orm.session.add(a_log)
    orm.session.commit()

    return resp


@api.route('/domains/<dm_id>/cache_settings')
def list_domain_cache_setting(dm_id):
    # project_id = request.args['project_id']
    dcs = DomainCache.query.filter_by(domain_id=dm_id)
    orm.session.commit()

    resp = {
        'status': 0,
        'msg': 'success',
        'data': [dc.to_json() for dc in dcs],
    }
    return resp


@api.route('/domains/<dm_id>/cache_settings/<dc_id>', methods=['PATCH'])
def update_domain_cache_setting(dm_id, dc_id):
    username = request.headers['user_name']

    dc = DomainCache.query.filter_by(domain_id=dm_id,
                                     domain_cache_id=dc_id).first_or_404()

    req_data = request.get_json(force=True)
    attr, value = req_data.items().pop()

    if attr not in DomainCache._get_columns():
        abort(400)

    try:
        setattr(dc, attr, value)
        orm.session.commit()
        resp = {
            'status': 0,
            'msg': 'success',
            'data': dc.to_json(),
        }
    except Exception, e:
        orm.session.trollback()
        LOGGER.exception(e.message)
        resp = {
            'status': 2,
            'msg': 'fail',
            'data': 'update failed!',
        }

    # Add action log
    a_log = ActionLog()
    a_log.username = username
    a_log.action_name = u'更新缓存规则'
    a_log.resource_type = 'domain'
    a_log.resource_id = dm_id
    a_log.result = resp['msg']
    orm.session.add(a_log)

    return resp


@api.route('/action_logs', methods=['GET'])
def get_action_logs():
    """ Get action logs.

    Action logs filtered by `resource_type` and `resource_id`.
    then split them to pages of size 10(default),
    page 1(default) is returned.

        GET /api/action_logs?t=domain&i=dm-123&ps=10&pi=1

    """
    args = request.args
    resource_id = args['i']
    resource_type = args['t']

    page_size = int(args.get('ps', 10))
    page_index = int(args.get('pi', 1))

    query = ActionLog.query.filter_by(resource_id=resource_id,
                                     resource_type=resource_type)
    logs = query.order_by(orm.text('-action_at')).limit(page_size).offset((page_index-1)*page_size)
    return {
        'status': 0,
        'msg': 'ok',
        'data': [log.to_json(['id']) for log in logs],
    }
